<!--
 * @moduleName: 下拉树组件
 * @Author: dawdler
 * @Date: 2018-12-19 14:03:03
 * @LastModifiedBy: dawdler
 * @LastEditTime: 2019-04-01 15:58:58
 -->
<template>
  <div class="el-tree-select">
    <!-- 下拉文本 -->
    <el-select
      :collapse-tags="collapseTags"
      :clearable="clearable"
      style="width: 100%"
      :style="styles"
      class="el-tree-select-input"
      v-model="labels"
      :disabled="disabled"
      popper-class="select-option"
      ref="select"
      v-bind="selectParams"
      :popper-append-to-body="false"
      :filterable="false"
      v-popover:popover
      @remove-tag="_selectRemoveTag"
      @clear="_selectClearFun"
      @focus="_popoverShowFun"
      @visible-change="_visibleChange"
    ></el-select>
    <!-- 弹出框 -->
    <el-popover
      :disabled="disabled"
      ref="popover"
      :placement="placement"
      popper-class="el-tree-select-popper"
      :width="width"
      v-model="visible"
      trigger="click"
    >
      <!-- 是否显示搜索框 -->
      <el-input
        v-if="treeParams.filterable"
        v-model="keywords"
        size="mini"
        class="input-with-select mb10"
        @change="_searchFun"
      >
        <!--                <el-button slot="append" icon="el-icon-search"></el-button>-->
      </el-input>
      <el-scrollbar
        tag="div"
        wrap-class="el-select-dropdown__wrap"
        view-class="el-select-dropdown__list"
        class="is-empty"
      >
        <!-- 树列表 -->
        <el-tree
          ref="tree"
          v-show="data.length > 0"
          v-bind="treeParams"
          :data="data"
          :highlight-current="false"
          :node-key="propsValue"
          :default-expanded-keys="defaultExpandedKeys"
          :default-checked-keys="selectParams.multiple ? ids : null"
          :draggable="false"
          :current-node-key="ids.length > 0 ? ids[0] : ''"
          :show-checkbox="selectParams.multiple"
          :filter-node-method="_filterFun"
          @node-click="_treeNodeClickFun"
          @check="_treeCheckFun"
        ></el-tree>
        <!-- 暂无数据 -->
        <div v-if="data.length === 0" class="no-data">暂无数据</div>
      </el-scrollbar>
    </el-popover>
  </div>
</template>
<style>
.el-tree-select .select-option {
  display: none !important;
}

.el-tree-select-popper {
  max-height: 400px;
  overflow: auto;
}

.el-tree-select-popper .el-button--small {
  width: 25px !important;
  min-width: 25px !important;
}

.el-tree-select-popper[x-placement^="bottom-start"] {
  margin-top: 5px;
}

.mb10 {
  margin-bottom: 10px;
}

.no-data {
  height: 32px;
  line-height: 32px;
  font-size: 14px;
  color: #cccccc;
  text-align: center;
}
</style>
<script>
import { on, off } from "./utils/dom";
import { each } from "./utils/utils";
// @group api
export default {
  name: "ElTreeSelect",
  props: {
    // v-model,存储的是treeParams.data里面的id
    value: {
      // `String` / `Array`
      type: [String, Number, Array],
      // `''`
      default() {
        return "";
      },
    },
    // el-select样式
    styles: {
      type: Object,
      // {}
      default() {
        return {};
      },
    },
    defaultLabel: {
      type: Array,
      default() {
        return [];
      }
    },
    // 是否禁用文本框
    disabled: {
      type: Boolean,
      // false
      default() {
        return false;
      },
    },
    clearable: {
      type: Boolean,
      // false
      default() {
        return true;
      },
    },
    expandedLevel:{
      type: Number,
      default: 2
    },
    // 弹出框位置
    placement: {
      type: String,
      //  bottom
      default() {
        return "bottom-start";
      },
    },
    popoverWidth: {
      type: [String, Number],
      default: "",
    },
    collapseTags:{
      type:Boolean,
      default:true
    },
    /*
        文本框参数，几乎支持el-select所有的API<br>
        取消参数：<br>
        设定下拉框的弹出框隐藏：<br>
        `:popper-append-to-body="false"` <br>
        搜索从弹出框里面执行： <br>
        `:filterable="false"`
        */
    selectParams: {
      type: Object,
      /*
            Object默认参数：<br><br>
            是否多选：<br>
            `multiple: true`<br><br>
            是否可以清空选项：<br>
            `clearable: true,`<br><br>
            是否禁用：<br>
            `disabled: false,`<br><br>
            搜索框placeholder文字：<br>
            `placeholder: '请选择',`<br><br>
            */
      default() {
        return {
          multiple: true,
          clearable: true,
          disabled: false,
          placeholder: "请选择",
        };
      },
    },
    /*
        下拉树参数，几乎支持el-tree所有的API<br>
         取消参数:<br>
        `:show-checkbox="selectParams.multiple"`<br>
        使用下拉框参数multiple判断是否对树进行多选<br>
        取消对el-tree的人为传参show-checkbox<br>
        `:node-key="propsValue"`     自动获取treeParams.props.value<br>
        `:draggable="false"`         屏蔽拖动
        */
    treeParams: {
      type: Object,
      /*
            Object默认参数：<br><br>
            在有子级的情况下是否点击父级关闭弹出框,false 只能点击子级关闭弹出框：`clickParent: false`<br><br>
            是否显示搜索框：<br>
            `filterable: false`<br><br>
            下拉树的数据：<br>
            `data:[]`<br><br>
            下拉树的props：<br>
            `props: {`<br>
                `children: 'children',`<br>
                `label: 'name',`<br>
                `value: 'flowId',`<br>
                `disabled: 'disabled'`<br>
            `}`
            */
      default() {
        return {
          clickParent: false,
          filterable: false,
          data: [],
          props: {
            children: "children",
            label: "name",
            value: "flowId",
            disabled: "disabled",
          },
        };
      },
    },
  },
  data() {
    return {
      propsValue: "flowId",
      propsLabel: "name",
      propsDisabled: "disabled",
      propsChildren: "children",
      data: [],
      keywords: "",
      labels: "", // 存储名称，用于下拉框显示内容
      ids: [""], // 存储id
      selectNodes: [""], // 选中数据
      visible: false, // popover v-model
      width: 150,
      treeData:[],
      defaultExpandedKeys:[]
    };
  },
  watch: {
    data: {
        handler(val) {
          if (val && val.length > 0) {
            this._getExpandedKeys(val)
            // this.$nextTick(() => {
            //   this.$refs.tree.setCurrentKey(val[0][this.propsValue])
            // })
          }
        },
        immediate: true
    },
    ids: function (val) {
      if (val !== undefined) {
        this._setSelectNodeFun(val);
      }
    },
    value: function (val) {
      if (this.ids !== val) {
        if (this.selectParams.multiple) {
          this.ids = val;
        } else {
          this.ids = val === "" ? [] : [val];
        }
      }
    },
    keywords(val) {
      this.$refs.tree.filter(val);
    },
    treeParams: {
      handler(val) {
        const { props, data } = val;
        this.propsValue = props.value;
        this.propsLabel = props.label;
        this.propsDisabled = props.disabled;
        this.propsChildren = props.children;
        this.data = data.length > 0 ? [...data] : [];
        if (props.defaultValue === "orgSN" && data.length > 0) {
          this.ids.push(data[0].orgSN);
        }
      },
      deep: true,
      immediate: true,
    },
    defaultLabel(value){
      this.labels = value.length > 0 ? value : []
    }
  },
  created() {
    const { multiple } = this.selectParams;
    if (multiple) {
      this.labels = this.defaultLabel.length > 0 ? this.defaultLabel : []
      this.ids = this.value
      // console.log('label')
      // console.log(this.defaultLabel)
    } else {
      this.labels = "";
      this.ids = this.value instanceof Array ? this.value : [this.value];
    }
  },
  mounted() {
    this._updateH();
    this.$nextTick(() => {
      on(document, "mouseup", this._popoverHideFun);
    });
  },
  methods: {
    // 输入文本框输入内容抛出
    _searchFun() {
      /*
            对外抛出搜索方法，自行判断是走后台查询，还是前端过滤<br>
            前端过滤：this.$refs.treeSelect.$refs.tree.filter(value);<br>
            后台查询：this.$refs.treeSelect.treeDataUpdateFun(data);
            */
      this.$emit("searchFun", this.keywords);
    },
     _getExpandedKeys(data, level = 1) {
        data.forEach(item => {
          if (level < this.expandedLevel) {
            if(this.defaultExpandedKeys.indexOf(item[this.propsValue]) === -1){
              this.defaultExpandedKeys.push(item[this.propsValue])
            }

            if (item.children) {
              this._getExpandedKeys(item.children, level + 1)
            }
          }
        })
      },
    //  根据id筛选当前树名称，以及选中树列表
    _setSelectNodeFun(ids) {
      const el = this.$refs.tree;
      if (!el) {
        throw new Error("找不到tree dom");
      }
      const { multiple } = this.selectParams;
      // 长度为0，清空选择
      if (ids.length === 0 || this.data.length === 0) {
        this.labels = multiple ? [] : "";
        if (multiple) {
          el.setCheckedKeys([]);
        } else {
          el.setCurrentKey("");
        }
        return;
      }
      if (multiple) {
        el.setCheckedKeys(ids);
        this.labels = el.getCheckedNodes().map((item) => item[this.propsLabel]) || [];
      } else {
        el.setCurrentKey(ids[0]);
        if (el.getCurrentNode()) {
          this.labels = el.getCurrentNode()[this.propsLabel];
        } else {
          this.labels = "";
        }
      }
      this._updatePopoverLocationFun();
    },
    // 更新popover位置
    _updatePopoverLocationFun() {
      // dom高度还没有更新，做一个延迟
      setTimeout(() => {
        this.$refs.popover.updatePopper();
      }, 50);
    },
    // 树过滤
    _filterFun(value, data, node) {
      if (!value) return true;
      return data[this.propsLabel].indexOf(value) !== -1;
    },
    // 树点击
    _treeNodeClickFun(data, node, vm) {

      const { multiple } = this.selectParams;
      const { clickParent } = this.treeParams;
      const { propsValue, propsChildren, propsDisabled } = this;
      if (data[propsDisabled]) {
        // 禁用
        return;
      }
      if (node.checked) {
        const value = data[this.propsValue];
        this.ids = this.ids.filter((id) => id !== value);
      } else {
        if (!multiple) {
          // 多选，不关闭，单选，判断是否允许点击父级关闭弹出框
          if (!clickParent) {
            const children = data[propsChildren];
            // 如果不允许点击父级,自身为末级，允许点击之后关闭
            if (!children || children.length === 0) {
              this.ids = [data[propsValue]];
              this.visible = false;
            } else {
              // 不允许父级，阻止继续派发
              return false;
            }
          } else {
            this.ids = [data[propsValue]];
            this.visible = false;
          }
        } else {
          this.ids.push(data[propsValue]);
        }
      }
      this._emitFun();
      /*
            点击节点，对外抛出   `data, node, vm`<br>
            `data:` 当前点击的节点数据<br>
            `node:` 当前点击的node<br>
            `vm:` 当前组件的vm
            */
      this.$emit("node-click", data, node, vm);
    },
    // 树勾选
    _treeCheckFun(data, node, vm) {
      this.ids = [];
      const { propsValue } = this;
      node.checkedNodes.forEach((item) => {
        this.ids.push(item[propsValue]);
      });
      /*
            点击复选框，对外抛出   `data, node, vm`<br>
            `data:` 当前点击的节点数据<br>
            `node:` 当前点击的node<br>
            `vm:` 当前组件的vm
            */
      this.$emit("check", data, node, vm);
      this._emitFun();
    },
    // 下拉框移除tag时触发
    _selectRemoveTag(tag) {
      const { data, propsValue, propsLabel, propsChildren } = this;
      each(
        data,
        (item) => {
          if (item[propsLabel] === tag) {
            const value = item[propsValue];
            this.ids = this.ids.filter((id) => id !== value);
          }
        },
        propsChildren
      );
      this.$refs.tree.setCheckedKeys(this.ids);
      this._emitFun();
    },
    // 下拉框清空数据
    _selectClearFun() {
      this.ids = [];
      const { multiple } = this.selectParams;
      // 下拉框清空，对外抛出``this.$emit('input', multiple ? [] : '');`
      this.$emit("input", multiple ? [] : "");
      // 下拉框清空，对外抛出``this.$emit('select-clear');`
      this.$emit("select-clear");
      this._updatePopoverLocationFun();
    },
    _visibleChange(){
      if(this.treeParams.filterable){
         //显示时，清除搜索框内的值
      this.$emit("search-clear");
      }

    },
    // 判断类型，抛出当前选中id
    _emitFun() {
      const { multiple } = this.selectParams;
      this.$emit("input", multiple ? this.ids : this.ids.length > 0 ? this.ids[0] : "");
      this._updatePopoverLocationFun();
    },
    // 更新宽度
    _updateH() {
      this.$nextTick(() => {
        if (this.popoverWidth) {
          this.width = this.popoverWidth;
        } else {
          this.width = this.$refs.select.$el.getBoundingClientRect().width;
        }
      });
    },
    // 显示弹出框的时候容错，查看是否和el宽度一致
    _popoverShowFun() {
      this._updateH();
    },

    // 判断是否隐藏弹出框
    _popoverHideFun(e) {
      if(e&&e.path){
      let isInter = e.path.some((list) => {
        if(list.className && typeof(list.className) === 'string'){
           return  list.className && list.className.indexOf("el-tree-select") !== -1;
        }else{
          return false
        }
      });
      if (!isInter) {
        this.visible = false;
      }
      }

    },
    /**
     * @vuese
     * 树列表更新数据
     * @arg Array
     */
    treeDataUpdateFun(data) {
      this.data = data;
      // 数据更新完成之后，判断是否回显内容
      setTimeout(() => {
        this._setSelectNodeFun(this.ids);
      }, 300);
    },

    /**
     * @vuese
     * 本地过滤方法
     * @arg String
     */
    filterFun(val) {
      this.$refs.tree.filter(val);
    },
  },
  components: {},
  beforeDestroy() {
    off(document, "mouseup", this._popoverHideFun);
  },
};
</script>
